package com.itobase.questionnaire.service.impl;


import com.itobase.questionnaire.VO.BaseInfo;
import com.itobase.questionnaire.VO.UserBaseVO;
import com.itobase.questionnaire.dto.MarkDTO;
import com.itobase.questionnaire.exception.BussinessException;
import com.itobase.questionnaire.exception.WrongParameterException;
import com.itobase.questionnaire.model.SurveyGroup;
import com.itobase.questionnaire.model.Tag;
import com.itobase.questionnaire.model.auth.User;
import com.itobase.questionnaire.repository.*;
import com.itobase.questionnaire.service.IUserService;
import com.itobase.questionnaire.template.Constant;
import com.itobase.questionnaire.template.Page;
import com.itobase.questionnaire.util.ExcelUtil;
import com.itobase.questionnaire.util.MD5Util;
import com.itobase.questionnaire.util.PropertiesUtil;
import com.itobase.questionnaire.util.StringUtil;
import com.mongodb.BasicDBList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.data.mongodb.core.query.Criteria.where;

@Service
public class UserService implements IUserService {
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    UserRepository userRepository;
    @Autowired
    TagRepository tagRepository;
    @Autowired
    PersonGroupRepository personGroupRepository;
    @Autowired
    SurveyGroupRepository surveyGroupRepository;
    @Autowired
    SurveyRepository surveyRepository;

    public User findByUsername(String username) {

        return userRepository.findByUsername(username);
    }


    /**
     * 单个添加user
     *
     * @param user
     * @return
     */
    public Integer insert(User user) {
        User user1 = userRepository.findByUsername(user.getUsername());
        if (user1 != null)
            throw new WrongParameterException("该用户已存在");
        user.setPassword(MD5Util.encode(user.getLongPhone()));
        user.setFlag(true);
        userRepository.insert(user);
        return 1;
    }

    @Override
    public List<User> getUsersByCriteria(String conditions) {
        // TODO: 2018/8/4  访问人员组织系统的接口获取userList；
        return null;
    }


    /**
     * 根据用户的id以及调查绑定的调查组获取人员的基本信息和人员类型
     *
     * @param ids
     * @param surveyGroupId
     * @return
     */
    @Override
    public List<BaseInfo> getUserInfoByIds(List<String> ids, String surveyGroupId) {
        List<User> userList = userRepository.findByIdIn(ids.toArray(new String[0]));
        List<BaseInfo> infoList = new ArrayList<>();
        SurveyGroup groupUser = surveyGroupRepository.findOne(surveyGroupId);
        Map<String, String> flatTypeGroup = new HashMap<>();//key为userId,value 为type,和typeGroup相反
        BaseInfo baseInfo;
        if (groupUser != null) {
            Map<String, List<String>> typeGroup = groupUser.getGroup();
            List<String> userIds;
            /*
             * 将surveyGroup展开，并将userid作为key，方便获取****
             */
            for (String key : typeGroup.keySet()) {
                userIds = typeGroup.get(key);
                if (userIds == null) {
                    continue;
                }
                for (String e : userIds) {
                    if (!flatTypeGroup.containsKey(e)) {
                        flatTypeGroup.put(e, key);
                    } else {
                        /*
                        如果一个人有两个type，将返回一个人的两个userInfo
                         */
                        if (ids.contains(e)) {
                            User user = Optional.ofNullable(userRepository.findOne(e)).orElseThrow(() -> new RuntimeException("人员id错误"));
                            baseInfo = user2BaseInfo(user);
                            baseInfo.setType(key);
                            infoList.add(baseInfo);
                        }
                    }
                }
            }
        }
        for (User user : userList) {
            baseInfo = user2BaseInfo(user);
            baseInfo.setType(flatTypeGroup.get(user.getId()));
            infoList.add(baseInfo);
        }
        return infoList;
    }

    private BaseInfo user2BaseInfo(User user) {
        BaseInfo baseInfo = new BaseInfo();
        baseInfo.setId(user.getId());
        baseInfo.setName(user.getName());
        baseInfo.setPhone(user.getLongPhone());
        return baseInfo;
    }


    /**
     * 添加用户
     *
     * @param file
     * @param userTypeId
     * @return
     */
    public Integer addUsersByExcel(MultipartFile file, String userTypeId) {
        File file1 = null;
        try {
            file1 = File.createTempFile("tmp", null);
            file.transferTo(file1);
            if (ExcelUtil.isExcel2007(file1.getPath()))
                throw new BussinessException("暂只支持.xls格式的excel");
        } catch (IOException e) {
            e.printStackTrace();
        }
        Optional.ofNullable(personGroupRepository.findOne(userTypeId)).orElseThrow(() -> new WrongParameterException("传入id错误"));
        String userType = personGroupRepository.findOne(userTypeId).getGroupName();
        List<User> newUsers = new ArrayList<>();
        if (userType.equals("学生")) {
            newUsers = ExcelUtil.readStudentXls(file1);
        } else if (userType.equals("老师")) {
            newUsers = ExcelUtil.readTeacherExcel(file1);
        } else if (userType.equals("研究生")) {
            newUsers = ExcelUtil.readPostGraduateExcel(file1);
        }
        // 查重
        List<User> existedUsers = new ArrayList<>();
        for (User user : newUsers) {
            User oldUser = userRepository.findByUsername(user.getUsername());
            if (oldUser != null)
                existedUsers.add(user);
            user.setUserTypeId(userTypeId);
            user.setPassword(MD5Util.encode(user.getLongPhone()));
        }
        if (existedUsers.size() != 0) {
            StringBuilder stringBuilder = new StringBuilder();
            for (User user : existedUsers)
                stringBuilder.append(user.getName() + " ");
            throw new WrongParameterException("下列角色" + stringBuilder.toString() + "已存在,请在excel中删除后重新添加");
        }
        userRepository.save(newUsers);
        file1.deleteOnExit();
        return newUsers.size();
    }


    /**
     * 获取人员列表
     *
     * @param userTypeId
     * @return
     */
    @Override
    public Page<UserBaseVO> getUser(Pageable pageable, String userTypeId, String keyWord) {
        Boolean existed = StringUtil.isNotEmpty(userTypeId);
        List<User> userList = new ArrayList<>();
        long count = 0;
        BasicDBList dbList = new BasicDBList();
        dbList.add(Constant.TEACID);
        dbList.add(Constant.STUID);
        dbList.add(Constant.GRADUATE_STUDENT_ID);
        if (existed)
            Optional.ofNullable(personGroupRepository.findOne(userTypeId))
                    .orElseThrow(() -> new WrongParameterException("id不存在"));
        if (StringUtil.isEmpty(keyWord)) {
            if (existed) {
                userList = userRepository.findByUserTypeId(userTypeId, pageable).getContent();
                count = userRepository.findByUserTypeId(userTypeId, pageable).getTotalElements();
            } else {
                Criteria keyWordCriteria = new Criteria().orOperator(where("userTypeId").in(dbList));
                userList = mongoTemplate.find(Query.query(keyWordCriteria).with(pageable), User.class);
                count = mongoTemplate.count(Query.query(keyWordCriteria).with(pageable), User.class);
            }
        } else {
            Criteria keyWordCriteria = new Criteria().orOperator(
                    where("username").regex(keyWord),
                    where("name").regex(keyWord),
                    where("collegeName").regex(keyWord),
                    where("longPhone").regex(keyWord),
                    where("className").regex(keyWord),
                    where("level").regex(keyWord),
                    where("major").regex(keyWord),
                    where("gender").regex(keyWord)
            );
            if (existed) {
                keyWordCriteria.andOperator(where("userTypeId").is(userTypeId));
                userList = mongoTemplate.find(Query.query(keyWordCriteria).with(pageable), User.class);
                count = mongoTemplate.count(Query.query(keyWordCriteria), User.class);
            } else {
                keyWordCriteria.andOperator(where("userTypeId").in(dbList));
                userList = mongoTemplate.find(Query.query(keyWordCriteria).with(pageable), User.class);
                count = mongoTemplate.count(Query.query(keyWordCriteria), User.class);
            }
        }
        Page<UserBaseVO> page = new Page<>();
        page.setTotalCount(count);
        page.setData(user2UserVO(userList));
        return page;
    }

    /**
     * 禁用用户
     *
     * @param userId
     */
    public void offUser(String userId) {
        Optional.ofNullable(userRepository.findOne(userId))
                .orElseThrow(() -> new WrongParameterException("传入参数错误"));
        User user = userRepository.findOne(userId);
        user.setFlag(false);
        userRepository.save(user);
    }

    /**
     * 删除用户
     *
     * @param userId
     */
    @Override
    public void deleteUser(String userId) {
        Optional.ofNullable(userRepository.findOne(userId))
                .orElseThrow(() -> new WrongParameterException("传入参数错误"));
        List<SurveyGroup> surveyGroupList = surveyGroupRepository.findAll();
        for (SurveyGroup surveyGroup : surveyGroupList) {
            if (surveyGroup.getGroup() == null)
                continue;
            for (Map.Entry<String, List<String>> entry : surveyGroup.getGroup().entrySet()) {
                if (entry.getValue() == null)
                    continue;
                for (String existedUserId : entry.getValue()) {
                    if (existedUserId.equals(userId))
                        throw new WrongParameterException("该用户已被导入调查组,不能删除");
                }
            }
        }
        userRepository.delete(userId);
    }

    /**
     * 批量给人打上标签
     *
     * @param markDTO
     */
    @Override
    public void mark(MarkDTO markDTO) {
        markDTO.getTagIds().forEach(tagId -> {
            markDTO.getUserIds().forEach(userId -> {
                Tag tag = tagRepository.findOne(tagId);
                User user = userRepository.findOne(userId);
                List<Tag> existTag = user.getTag();
                if (existTag.size() == 0 || existTag == null) {
                    List<Tag> tagList = new ArrayList<>();
                    tagList.add(tag);
                    user.setTag(tagList);
                } else {
                    if (existTag.contains(tag))
                        throw new BussinessException("该用户" + user.getName() + "已存在该标签");
                    else {
                        existTag.add(tag);
                        user.setTag(existTag);
                    }
                }
                userRepository.save(user);
            });
        });
    }

    /**
     * 校验人员有无重复
     */
    @Override
    public void check() {
        List<User> userList = userRepository.findAll();
        List<String> phone = new ArrayList<>();
        for (int i = 0; i < userList.size(); i++) {
            User user = userList.get(i);
            for (int j = i + 1; j < userList.size(); j++) {
                User user1 = userList.get(j);
                if (user.getLongPhone().equals(user1.getLongPhone())) {
                    if (!phone.contains(user.getLongPhone()))
                        phone.add(user.getLongPhone());
                }
            }
        }
        if (phone.size() > 0) {
            phone.forEach(System.out::println);
        }
    }

    /**
     * 随机抽取每个学院学生详情
     *
     * @return
     */
    @Override
    public Map<String, List<User>> getRangeUser(Integer number, String userTypeId) {
        List<User> students = userRepository.findByUserTypeId(Constant.STUID);
        Map<String, List<User>> rangeUser = new HashMap<>();
        Random index = new Random();
        students.stream().collect(Collectors.groupingBy(User::getCollegeName)).entrySet().forEach(entry -> {
            List<User> studentOne = entry.getValue();
            List<User> selectedStu = new ArrayList<>();
            List<Integer> indexList = new ArrayList<>();
            if (studentOne.size()<10){

            }else {
                for (int i = 0, j; i < number; i++) {
                    j = index.nextInt(studentOne.size());
                    if (!indexList.contains(j)) {
                        indexList.add(j);
                        selectedStu.add(studentOne.get(j));
                    } else {
                        i--;
                    }
                }
                rangeUser.put(entry.getKey(), selectedStu);
            }

        });
        return rangeUser;
    }

    @Override
    public Map<String,List<String>> getRangeId(Integer number, String userTypeId) {
        List<User> studentList = userRepository.findByUserTypeId(Constant.GRADUATE_STUDENT_ID);
        List<User> students = studentList
                .stream()
                .filter(user -> user.getCollegeName()!=null)
                .collect(Collectors.toList());
        List<String> rangeStuId = new ArrayList<>();
        List<String> rangeStuPhone = new ArrayList<>();
        List<String> check = new ArrayList<>();
        Map<String,List<String>> map = new HashMap<>();

        Random index = new Random();
        students.stream().collect(Collectors.groupingBy(User::getCollegeName)).entrySet().forEach(entry -> {
            List<User> studentOne = entry.getValue();
            List<User> selectedStu = new ArrayList<>();
            List<Integer> indexList = new ArrayList<>();
                for (int i = 0, j; i < number; i++) {
                    j = index.nextInt(studentOne.size());
                    if (!indexList.contains(j)) {
                        indexList.add(j);
                        selectedStu.add(studentOne.get(j));
                    } else {
                        i--;
                    }
                }
                selectedStu.forEach(user -> rangeStuId.add(user.getId()));
        });

        rangeStuId.forEach(id-> rangeStuPhone.add(userRepository.findOne(id).getLongPhone()));
        rangeStuId.forEach(id-> check.add(userRepository.findOne(id).getUserTypeId()));

/*
        Set<String> set = new HashSet<>();
        students.forEach(user->{
            if (user.getLongPhone().startsWith("1") && user.getLongPhone().length()==11 && user.getLongPhone()!=""){
                if (user.getUsername().startsWith("sh")) {
                    if (set.add(user.getLongPhone())) {
                        rangeStuId.add(user.getId());
                        rangeStuPhone.add(user.getLongPhone());
                    }

                }
            }
        });
*/
        map.put("id",rangeStuId);
        map.put("phone",rangeStuPhone);
        map.put("type",check);
        return map;

    }

    /**
     * 保存文件
     *
     * @param file
     * @return
     */
    private File saveFile(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        //获取扩展名
        String fileExtensionName = fileName.substring(fileName.lastIndexOf("."));
        String uploadFileName = UUID.randomUUID() + fileExtensionName;
        String path = PropertiesUtil.getProperty("path");

        File fileDir = new File(path);
        if (!fileDir.exists()) {
            fileDir.setWritable(true);
            fileDir.mkdirs();
        }
        File targetFile = new File(path, uploadFileName);
        return targetFile;
    }

    /**
     * 封装
     *
     * @param userList
     * @return
     */
    private List<UserBaseVO> user2UserVO(List<User> userList) {
        List<UserBaseVO> userBaseVOList = new ArrayList<>();
        userList.stream().forEach(user -> userBaseVOList.add(new UserBaseVO().reconvert(user)));
        return userBaseVOList;
    }
}
